package service

import (
	"errors"
	"math"
	"server_cluster/http/model"
	"sort"
	"time"

	"gorm.io/gorm"
	"server_cluster/common/logger"
)

const (
	TowerRankNum = 200
	RankLimitNum = 100
)

var TotalUserNum int64
var RankOffset int64
var TempTowerRank []*model.DbTowerRank

func (s *Service) GetTowerRank(uid uint32) (*model.TowerRank, error) {
	selfTowerRank, err := s.d.QueryTowerRankByUid(uid)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			selfTowerRank = &model.DbTowerRank{
				Uid:           int32(uid),
				NickName:      "",
				Rank:          0,
				RankPercent:   0,
				TowerArea:     0,
				TowerLevel:    0,
				TowerPassTime: 0,
			}
		} else {
			return nil, err
		}
	}
	towerRankList, err := s.d.QueryTowerRankList(TowerRankNum)
	if err != nil {
		return nil, err
	}
	rankList := make([]*model.RankEntry, 0)
	for _, towerRank := range towerRankList {
		rankList = append(rankList, &model.RankEntry{
			Uid:        towerRank.Uid,
			NickName:   towerRank.NickName,
			Rank:       towerRank.Rank,
			TowerArea:  towerRank.TowerArea,
			TowerLevel: towerRank.TowerLevel,
		})
	}
	ret := &model.TowerRank{
		RankList: rankList,
		SelfRank: &model.SelfRank{
			Uid:         selfTowerRank.Uid,
			NickName:    selfTowerRank.NickName,
			IsInRank:    selfTowerRank.Rank != 0 && selfTowerRank.Rank <= TowerRankNum,
			RankPercent: selfTowerRank.RankPercent,
			TowerArea:   selfTowerRank.TowerArea,
			TowerLevel:  selfTowerRank.TowerLevel,
		},
	}
	return ret, nil
}

func (s *Service) CalcTowerRank() error {
	logger.Warn("calc tower rank start")
	var err error
	TotalUserNum, err = s.d.QueryUserDataTotalNum()
	TempTowerRank = make([]*model.DbTowerRank, 0)
	if RankOffset != 0 {
		return nil
	}
	var playCount int32 = 0
	for RankOffset < TotalUserNum {
		userDataList, err := s.d.QueryUserDataList(RankLimitNum, int(RankOffset))
		if err != nil {
			return err
		}
		for _, userData := range userDataList {
			if userData.TowerPassTime == 0 {
				continue
			}
			TempTowerRank = append(TempTowerRank, &model.DbTowerRank{
				Uid:           userData.Uid,
				NickName:      userData.NickName,
				Rank:          0,
				RankPercent:   0,
				TowerArea:     userData.TowerArea,
				TowerLevel:    userData.TowerLevel,
				TowerPassTime: userData.TowerPassTime,
			})
			playCount++
		}
		sort.Slice(TempTowerRank, func(i, j int) bool {
			if TempTowerRank[i].TowerArea != TempTowerRank[j].TowerArea {
				return TempTowerRank[i].TowerArea > TempTowerRank[j].TowerArea
			}
			if TempTowerRank[i].TowerLevel != TempTowerRank[j].TowerLevel {
				return TempTowerRank[i].TowerLevel > TempTowerRank[j].TowerLevel
			}
			if TempTowerRank[i].TowerPassTime != TempTowerRank[j].TowerPassTime {
				return TempTowerRank[i].TowerPassTime < TempTowerRank[j].TowerPassTime
			}
			if TempTowerRank[i].Uid != TempTowerRank[j].Uid {
				return TempTowerRank[i].Uid < TempTowerRank[j].Uid
			}
			return true
		})
		TempTowerRank = TempTowerRank[:int(math.Min(float64(len(TempTowerRank)), float64(TowerRankNum)))]
		RankOffset += RankLimitNum
		time.Sleep(time.Second * 5)
	}
	err = s.d.ClearTowerRankTable()
	if err != nil {
		return err
	}

	for index, towerRank := range TempTowerRank {
		towerRank.Rank = int32(index + 1)
	}
	for _, towerRank := range TempTowerRank {
		towerRank.RankPercent = float32((towerRank.Rank)*1000/playCount) / 1000
	}
	err = s.d.InsertTowerRankList(TempTowerRank)
	if err != nil {
		return err
	}
	RankOffset = 0
	logger.Warn("calc tower rank finish")
	return nil
}
